package com.cloud.idGene;

/**
 * @Author tangyuan2meicloud.com
 * @DATE 2021/7/7 20:51
 * @Desc
 * @Remarks
 */
public class SnowIdGenerator {

//    雪花算法长度
    //    1 41 5 5 12

    private long roomid;
    private long comId;
    private long sequenceId;

    private long ROOM_BIT = 5L;
    private long MAX_ROOM_NUM = -1L ^ (-1L << ROOM_BIT);

    private long COM_BIT = 5L;
    private long MAX_COM_NUM = -1L ^ (-1L << COM_BIT);

    private long SEQ_BIT = 12L;
    private long MAX_SEQ_NUM = -1L ^ (-1L << SEQ_BIT);

    private final long START_TIME = 1625662780347L;

    private long lastTimeStamp = -1;

    public SnowIdGenerator(long roomid, long comId, long sequenceId) {
        if (roomid > MAX_ROOM_NUM) {
            throw new RuntimeException("机房ID初始值有误！");
        }
        if (comId > MAX_COM_NUM) {
            throw new RuntimeException("机器ID初始值有误！");
        }
        this.roomid = roomid;
        this.comId = comId;
        this.sequenceId = sequenceId;
    }

    public synchronized long generatorId() {
        long timeStamp = System.currentTimeMillis();
        if (timeStamp < lastTimeStamp) {
            throw new RuntimeException("时间错误");
        }
        if (timeStamp == lastTimeStamp) {
            sequenceId = sequenceId + 1 & MAX_SEQ_NUM;
            if (sequenceId == 0) { //到达最大生成数
                timeStamp = nextStamp(timeStamp);
            }
        } else {
            sequenceId = timeStamp & 1;
        }
        lastTimeStamp = timeStamp;
        long time = timeStamp - START_TIME;

        long id = time << (ROOM_BIT + COM_BIT + SEQ_BIT) | roomid << (COM_BIT + SEQ_BIT) | comId << SEQ_BIT | sequenceId;
        return id;
    }

    private long nextStamp(long timeStamp) {
        long now = System.currentTimeMillis();
        while (now <= timeStamp) {
            now = System.currentTimeMillis();
        }
        return now;
    }


    public static void main(String[] args) {
        long now = System.currentTimeMillis();

        SnowIdGenerator snowIdGeneratore = new SnowIdGenerator(1, 1, 1);
        for (int i = 0; i < 1000; i++) {
            System.out.println(snowIdGeneratore.generatorId());
        }
        System.out.println(System.currentTimeMillis() - now);
    }

}
